home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / ixemul-complete / ixemul / library / stackextend.c < prev    next >
C/C++ Source or Header  |  1996-08-13  |  10KB  |  368 lines

  1. #define    _KERNEL
  2. #include "ixemul.h"
  3.  
  4. #include <exec/memory.h>
  5. #include <signal.h>
  6. #include <unistd.h>
  7.  
  8. /*
  9.  * Glue asm to C.
  10.  */
  11. asm("
  12.     .globl    ___stkext
  13. ___stkext:
  14.     moveml    d0/d1/a0/a1/a6,sp@-
  15.     subqw    #4,sp        | sigset_t
  16.     jbsr    _atomic_on
  17.     subw    #12,sp        | struct StackSwapStruct
  18.     jbsr    _stkext
  19.     movel    4:W,a6
  20.     movel    sp,a0
  21.     jsr    a6@(-0x2dc)    | StackSwap(a0)
  22.     jbsr    _atomic_off
  23.     addqw    #4,sp        | StackSwapStruct is not copied
  24.     moveml    sp@+,d0/d1/a0/a1/a6
  25.     rts
  26.  
  27.     .globl    ___stkext_f    | see above
  28. ___stkext_f:
  29.     moveml    d0/d1/a0/a1/a6,sp@-
  30.     subqw    #4,sp
  31.     jbsr    _atomic_on
  32.     subw    #12,sp
  33.     jbsr    _stkext_f
  34.     movel    4:W,a6
  35.     movel    sp,a0
  36.     jsr    a6@(-0x2dc)
  37.     jbsr    _atomic_off
  38.     addqw    #4,sp
  39.     moveml    sp@+,d0/d1/a0/a1/a6
  40.       rts
  41.   
  42.     .globl    ___stkrst_f    | see above
  43. ___stkrst_f:
  44.     moveml    d0/d1/a0/a1/a6,sp@-
  45.     subqw    #4,sp
  46.     jbsr    _atomic_on
  47.     subw    #12,sp
  48.     jbsr    _stkrst_f
  49.     movel    4:W,a6
  50.     movel    sp,a0
  51.     jsr    a6@(-0x2dc)
  52.     jbsr    _atomic_off
  53.     addqw    #4,sp
  54.     moveml    sp@+,d0/d1/a0/a1/a6
  55.       rts
  56.   
  57.     .globl    ___stkrst
  58. ___stkrst:
  59.     moveml    d0/d1/a0/a1/a6,sp@-        | preserve registers
  60.     subqw    #4,sp        | make room for the signal mask
  61.     jbsr    _atomic_on    | disable all signals
  62.     subw    #12,sp        | make room for a StackSwapStruct
  63.     jbsr    _stkrst        | calculate either target sp or StackSwapStruct
  64.     tstl    d0        | set target sp?
  65.     jeq    swpfrm        | jump if not
  66.     movel    d0,a0        | I have a lot of preserved registers and
  67.                 | returnadresses on the stack. It's necessary
  68.                 | to copy them to the new location
  69.     moveq    #6,d0        | 1 rts, 5 regs and 1 signal mask to copy (2+5+1)-1=7
  70.     lea    sp@(40:W),a1    | get address of uppermost byte+1 (1+5+1)*4+12=40
  71.     cmpl    a0,a1        | compare with target location
  72.     jls    lp1        | jump if source<=target
  73.     lea    a0@(-28:W),a0    | else start at lower bound (1+5+1)*4=28
  74.     lea    a1@(-28:W),a1
  75.     movel    a0,sp        | set sp to reserve the room
  76. lp0:    movel    a1@+,a0@+    | copy with raising addresses
  77.     dbra    d0,lp0        | as long as d0>=0.
  78.     jra    endlp        | ready
  79. lp1:    movel    a1@-,a0@-    | copy with falling addresses
  80.     dbra    d0,lp1        | as long as d0>=0
  81.     movel    a0,sp        | finally set sp
  82.     jra    endlp        | ready
  83. swpfrm:    movel    4:W,a6        | If sp wasn't set call StackSwap()
  84.     movel    sp,a0
  85.     jsr    a6@(-0x2dc)
  86. endlp:    jbsr    _atomic_off    | reenable signals
  87.     addqw    #4,sp        | adjust sp
  88.     moveml    sp@+,d0/d1/a0/a1/a6        | restore registers
  89.     rts            | and return
  90. ");
  91.  
  92. void __stkrst_f(void);
  93.  
  94. #define    STK_UPPER    \
  95. (u.u_stk_used != NULL ? u.u_stk_used->upper : u.u_org_upper)
  96.  
  97. #define    STK_LOWER    \
  98. (u.u_stk_used != NULL ? (void *)(u.u_stk_used + 1) : u.u_org_lower)
  99.  
  100. #define    stk_safezone    6144    /* into ixprefs? */
  101. #define    stk_minframe    32768
  102.  
  103. void initstack(void)
  104. {
  105.   struct Process *me;
  106.   APTR lower, upper;
  107.  
  108.   me = (struct Process *)SysBase->ThisTask;
  109.  
  110.   u.u_tc_splower = me->pr_Task.tc_SPLower;
  111.   u.u_tc_spupper = me->pr_Task.tc_SPUpper;
  112.  
  113.   if (me->pr_CLI)
  114.   {
  115.     /* Process stackframe:
  116.      * me->pr_ReturnAddr points to size of stack (ULONG)
  117.      *         +4                  returnaddress
  118.      *         +8                  stackframe
  119.      */
  120.     lower = (char *)me->pr_ReturnAddr + 8 - *(ULONG *)me->pr_ReturnAddr;
  121.     upper = (char *)me->pr_ReturnAddr + 8;
  122.   }
  123.   else
  124.   {
  125.     lower = u.u_tc_splower;
  126.     upper = u.u_tc_spupper;
  127.   }
  128.  
  129.   u.u_org_lower = lower; /* Lower stack bound */
  130.   u.u_org_upper = upper; /* Upper stack bound +1 */
  131.   u.u_stk_used = NULL;   /* Stackframes in use */
  132.   u.u_stk_spare = NULL;  /* Spare stackframes */
  133.   u.u_stk_current=u.u_stk_max=0; /* No extended stackframes at this point */
  134.  
  135.   u.u_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
  136.   u.u_stk_argbt = 256; /* set some useful default */
  137. }
  138.  
  139. void __init_stk_limit(void **limit, unsigned long argbytes)
  140. {
  141.   u.u_stk_limit = limit;
  142.   u.u_stk_argbt = argbytes;
  143.   *limit = (char *)u.u_org_lower + stk_safezone + argbytes;
  144. }
  145.  
  146. /*
  147.  * Free all spare stackframes
  148.  */
  149. void freestack(void)
  150. {
  151.   struct stackframe *sf, *s2;
  152.  
  153.   sf = u.u_stk_spare;
  154.   u.u_stk_spare = NULL;
  155.   while (sf != NULL)
  156.   {
  157.     s2 = sf->next;
  158.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  159.     sf = s2;
  160.   }
  161. }
  162.  
  163. void __stkovf(void)
  164. {
  165.   u.u_stk_limit = NULL; /* disable stackextend from now on */
  166.   for (;;)
  167.     kill(getpid(), SIGSEGV); /* Ciao */
  168. }
  169.  
  170. /*
  171.  * Signal routines may want to benefit from stackextension too -
  172.  * so make all the stack handling functions atomic.
  173.  * FIXME: This seems to have the potential to break a Forbid() ?!?
  174.  */
  175. void atomic_on(sigset_t old)
  176. {
  177.   sigset_t fill;
  178.   sigfillset(&fill);
  179.   sigprocmask(SIG_SETMASK, &fill, &old);
  180. }
  181.  
  182. void atomic_off(sigset_t old)
  183. {
  184.   sigprocmask(SIG_SETMASK, &old, NULL);
  185. }
  186.  
  187. /*
  188.  * Move a stackframe with a minimum of requiredstack bytes to the used list
  189.  * and fill the StackSwapStruct structure.
  190.  */
  191. static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old)
  192. {
  193.   struct stackframe *sf;
  194.   ULONG recommendedstack;
  195.  
  196.   requiredstack += stk_safezone + u.u_stk_argbt;
  197.   if (requiredstack < stk_minframe)
  198.     requiredstack = stk_minframe;
  199.  
  200.   recommendedstack=u.u_stk_max-u.u_stk_current;
  201.   if (recommendedstack<requiredstack)
  202.     recommendedstack=requiredstack;
  203.  
  204.   for (;;)  
  205.   {
  206.     sf = u.u_stk_spare; /* get a stackframe from the spares list */
  207.     if (sf == NULL)
  208.     { /* stack overflown */
  209.       for (; recommendedstack>=requiredstack; recommendedstack/=2)
  210.       {
  211.     sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
  212.     if (sf != NULL)
  213.       break;
  214.       }
  215.       if (sf == NULL)
  216.       { /* and we have no way to extend it :-| */
  217.         sigprocmask(SIG_SETMASK, old, NULL);
  218.         __stkovf();
  219.       }
  220.       sf->upper = (char *)(sf + 1) + recommendedstack;
  221.       break;
  222.     }
  223.     u.u_stk_spare = sf->next;
  224.     if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
  225.       break;
  226.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  227.   }
  228.  
  229.   /* Add stackframe to the used list */
  230.   sf->next = u.u_stk_used;
  231.   u.u_stk_used = sf;
  232.   *u.u_stk_limit = (char *)(sf + 1) + stk_safezone + u.u_stk_argbt;
  233.  
  234.   /* prepare StackSwapStruct */
  235.   sss->stk_Pointer = sf->upper;
  236.   sss->stk_Lower = sf + 1;
  237.   sss->stk_Upper = (ULONG)sf->upper;
  238.  
  239.   /* Update stack statistics. */
  240.   u.u_stk_current += (char *)sf->upper - (char *)(sf + 1);
  241.   if (u.u_stk_current > u.u_stk_max)
  242.     u.u_stk_max = u.u_stk_current;
  243. }
  244.  
  245. /*
  246.  * Allocate a new stackframe with d0 bytes minimum.
  247.  */
  248. void stkext(struct StackSwapStruct sss, sigset_t old,
  249.  long d0, long d1, long a0, long a1, long a6, long ret1)
  250. {
  251.   void *callsp = &ret1 + 1;
  252.   int cpsize = (char *)callsp - (char *)&old;
  253.  
  254.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  255.     return; /* User intentionally left area of stackextension */
  256.  
  257.   pushframe(d0, &sss, &old);
  258.   *(char **)&sss.stk_Pointer -= cpsize;
  259.   CopyMem(&old, sss.stk_Pointer, cpsize);
  260. }
  261.  
  262. /*
  263.  * Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
  264.  * and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
  265.  */
  266. void stkext_f(struct StackSwapStruct sss, sigset_t old,
  267.  long d0, long d1, long a0, long a1, long a6, long ret1)
  268. {
  269.   void *argtop, *callsp = &ret1 + 1;
  270.   int cpsize;
  271.  
  272.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  273.     return; /* User intentionally left area of stackextension */
  274.  
  275.   argtop = (char *)callsp + u.u_stk_argbt;    /* Top of area with arguments */
  276.   if (argtop > STK_UPPER)
  277.     argtop = STK_UPPER;
  278.   cpsize = (char *)argtop - (char *)&old;
  279.  
  280.   pushframe(d0 + u.u_stk_argbt, &sss, &old);
  281.   *(char **)&sss.stk_Pointer -= cpsize;
  282.   CopyMem(&old,sss.stk_Pointer, cpsize);
  283.   u.u_stk_used->savesp = (char *)callsp + d1; /* store sp */
  284.   *(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
  285.     = &__stkrst_f; /* set returnaddress */
  286. }
  287.  
  288. /*
  289.  * Move all used stackframes upto (and including) sf to the spares list
  290.  * and fill the StackSwapStruct structure.
  291.  */
  292. static void popframes(struct stackframe *sf, struct StackSwapStruct *sss)
  293. {
  294.   struct stackframe *sf2;
  295.  
  296.   if (sf->next != NULL)
  297.   {
  298.     sss->stk_Lower = sf->next + 1;
  299.     sss->stk_Upper = (ULONG)sf->next->upper;
  300.     *u.u_stk_limit = (char *)(sf->next + 1) + stk_safezone + u.u_stk_argbt;
  301.   }
  302.   else
  303.   {
  304.     sss->stk_Lower = u.u_tc_splower;
  305.     sss->stk_Upper = (ULONG)u.u_tc_spupper;
  306.     *u.u_stk_limit = (char *)u.u_org_lower + stk_safezone + u.u_stk_argbt;
  307.   }
  308.   sf2 = u.u_stk_spare;
  309.   u.u_stk_spare = u.u_stk_used;
  310.   u.u_stk_used = sf->next;
  311.   sf->next = sf2;
  312.  
  313.   /* Update stack statistics. */
  314.   for (sf2 = u.u_stk_spare; sf2 != sf->next; sf2 = sf2->next)
  315.     u.u_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
  316. }
  317.  
  318. /*
  319.  * Set stackpointer back to some previous value
  320.  * != NULL: on the same stackframe (returns sp)
  321.  * == NULL: on another stackframe
  322.  */
  323. void *stkrst(struct StackSwapStruct sss, sigset_t old,
  324.  void *d0, long d1, long a0, long a1, long a6, long ret1)
  325. {
  326.   void *callsp = &ret1 + 1;
  327.   int cpsize = (char *)callsp - (char *)&old;
  328.   struct stackframe *sf1, *sf2;
  329.  
  330.   if (d0 >= STK_LOWER && d0 < STK_UPPER)
  331.     return d0;
  332.  
  333.   sf1 = u.u_stk_used;
  334.   if (sf1 == NULL)
  335.     return d0;
  336.   for (;;)
  337.   {
  338.     sf2 = sf1->next;
  339.     if (sf2 == NULL)
  340.     {
  341.       if (d0 < u.u_org_lower || d0 >= u.u_org_upper)
  342.         return d0;
  343.       break;
  344.     }
  345.     if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
  346.       break;
  347.     sf1 = sf2;
  348.   }
  349.   popframes(sf1, &sss);
  350.   sss.stk_Pointer = (char *)d0 - cpsize;
  351.   CopyMem(&old, sss.stk_Pointer,cpsize);
  352.   return NULL;
  353. }
  354.  
  355. /*
  356.  * return to last stackframe
  357.  */
  358. void stkrst_f(struct StackSwapStruct sss, sigset_t old,
  359.  long d0, long d1, long a0, long a1, long a6)
  360. {
  361.   void *callsp = &a6 + 1; /* This one has no returnaddress - it's a fallback for rts */
  362.   int cpsize = (char *)callsp - (char *)&old;
  363.  
  364.   sss.stk_Pointer = (char *)u.u_stk_used->savesp - cpsize;
  365.   popframes(u.u_stk_used, &sss);
  366.   CopyMem(&old, sss.stk_Pointer, cpsize);
  367. }
  368.